/*
 * Copyright (c) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/prctl.h>

#include "uvc_strm.h"

#include "hi_ext_util.h"
#include "histream.h"
#include "mpp_help.h"
#include "strm_isp.h"

#define U8FREQUENCY_NUM1        50
#define U8FREQUENCY_NUM2        60
#define FREQUENCY_SET_VALUE1    1
#define FREQUENCY_SET_VALUE2    2
#define AUTO_MODE_SET_VALUE     4
#define ANSOLUTE_TIME_SET_VALUE 100

/*************************************************************************************************
    Processing Unit Operation Functions
    来自sample，几乎未修改
*************************************************************************************************/
#define SP_STRM_ISP_PU

static uint16_t StrmBrightnessGet(void)
{
    ISP_CSC_ATTR_S stCSCAttr;

    HI_MPI_ISP_GetCSCAttr(0, &stCSCAttr);
    return (uint16_t)stCSCAttr.u8Luma;
}

static uint16_t StrmContrastGet(void)
{
    ISP_CSC_ATTR_S stCSCAttr;

    HI_MPI_ISP_GetCSCAttr(0, &stCSCAttr);
    return (uint16_t)stCSCAttr.u8Contr;
}

static uint16_t StrmHueGet(void)
{
    ISP_CSC_ATTR_S stCSCAttr;

    HI_MPI_ISP_GetCSCAttr(0, &stCSCAttr);
    return (uint16_t)stCSCAttr.u8Hue;
}

static uint8_t StrmPowerLineFrequencyGet(void)
{
    ISP_EXPOSURE_ATTR_S stExpAttr;

    HI_MPI_ISP_GetExposureAttr(0, &stExpAttr);
    if (stExpAttr.stAuto.stAntiflicker.u8Frequency != U8FREQUENCY_NUM1 &&
        stExpAttr.stAuto.stAntiflicker.u8Frequency != U8FREQUENCY_NUM2) {
        return 0;
    }
    return (stExpAttr.stAuto.stAntiflicker.u8Frequency == U8FREQUENCY_NUM1) ? 0x1 : 0x2;
}

static uint16_t StrmSaturationGet(void)
{
    ISP_CSC_ATTR_S stCSCAttr;

    HI_MPI_ISP_GetCSCAttr(0, &stCSCAttr);
    return (uint16_t)stCSCAttr.u8Satu;
}

static uint8_t StrmWhiteBalanceTemperatureAutoGet(void)
{
    ISP_WB_ATTR_S stWBAttr;

    HI_MPI_ISP_GetWBAttr(0, &stWBAttr);
    return (stWBAttr.enOpType == OP_TYPE_AUTO) ? 0x1 : 0x0;
}

static uint16_t StrmWhiteBalanceTemperatureGet(void)
{
    ISP_WB_INFO_S stWBInfo;

    HI_MPI_ISP_QueryWBInfo(0, &stWBInfo);
    return (uint16_t)stWBInfo.u16ColorTemp;
}

static void StrmBrightnessSet(uint16_t v)
{
    ISP_CSC_ATTR_S stCSCAttr;

    HI_MPI_ISP_GetCSCAttr(0, &stCSCAttr);
    stCSCAttr.u8Luma = v;
    HI_MPI_ISP_SetCSCAttr(0, &stCSCAttr);
}

static void StrmContrastSet(uint16_t v)
{
    ISP_CSC_ATTR_S stCSCAttr;

    HI_MPI_ISP_GetCSCAttr(0, &stCSCAttr);
    stCSCAttr.u8Contr = v;
    HI_MPI_ISP_SetCSCAttr(0, &stCSCAttr);
}

static void StrmHueSet(uint16_t v)
{
    ISP_CSC_ATTR_S stCSCAttr;

    HI_MPI_ISP_GetCSCAttr(0, &stCSCAttr);
    stCSCAttr.u8Hue = v;
    HI_MPI_ISP_SetCSCAttr(0, &stCSCAttr);
}

static void StrmPowerLineFrequencySet(uint8_t v)
{
    HI_S32 s32Ret;
    ISP_EXPOSURE_ATTR_S stExpAttr;

    HI_MPI_ISP_GetExposureAttr(0, &stExpAttr);
    if (v == 0) {
        stExpAttr.stAuto.stAntiflicker.bEnable = HI_FALSE;
    } else if (v == FREQUENCY_SET_VALUE1) {
        stExpAttr.stAuto.stAntiflicker.bEnable = HI_TRUE;
        stExpAttr.stAuto.stAntiflicker.u8Frequency = U8FREQUENCY_NUM1;
    } else if (v == FREQUENCY_SET_VALUE2) {
        stExpAttr.stAuto.stAntiflicker.bEnable = HI_TRUE;
        stExpAttr.stAuto.stAntiflicker.u8Frequency = U8FREQUENCY_NUM2;
    }

    s32Ret = HI_MPI_ISP_SetExposureAttr(0, &stExpAttr);
    if (s32Ret != HI_SUCCESS) {
        LOGE("HI_MPI_ISP_SetExposureAttr err 0x%x\n", s32Ret);
    }
}

static void StrmSaturationSet(uint16_t v)
{
    ISP_CSC_ATTR_S stCSCAttr;

    HI_MPI_ISP_GetCSCAttr(0, &stCSCAttr);
    stCSCAttr.u8Satu = v;
    HI_MPI_ISP_SetCSCAttr(0, &stCSCAttr);
}

static void StrmWhiteBalanceTemperatureAutoSet(uint8_t v)
{
    ISP_WB_ATTR_S stWBAttr;

    HI_MPI_ISP_GetWBAttr(0, &stWBAttr);
    stWBAttr.enOpType = (v == 1) ? OP_TYPE_AUTO : OP_TYPE_MANUAL;
    HI_MPI_ISP_SetWBAttr(0, &stWBAttr);
}

static void StrmWhiteBalanceTemperatureSet(uint16_t v)
{
    ISP_WB_INFO_S stWBInfo;
    ISP_WB_ATTR_S stWBAttr;
    HI_U16 u16ColorTemp;
    HI_U16 u16AWBGain[4];

    HI_MPI_ISP_QueryWBInfo(0, &stWBInfo);
    HI_MPI_ISP_GetWBAttr(0, &stWBAttr);

    u16ColorTemp = v;
    HI_MPI_ISP_CalGainByTemp(0, &stWBAttr, u16ColorTemp, 0, u16AWBGain);

    stWBAttr.enOpType = OP_TYPE_MANUAL;
    if (memcpy_s(&stWBAttr.stManual, sizeof(stWBAttr.stManual), u16AWBGain, sizeof(stWBAttr.stManual)) != EOK) {
        HI_ASSERT(0);
    }

    HI_MPI_ISP_SetWBAttr(0, &stWBAttr);
}

/*************************************************************************************************
    Input Terminal Operation Functions
    来自sample，几乎未修改
*************************************************************************************************/
#define SP_STRM_ISP_IT

static uint8_t StrmExposureAutoModeGet(void)
{
    ISP_EXPOSURE_ATTR_S stExpAttr;

    HI_MPI_ISP_GetExposureAttr(0, &stExpAttr);
    return (stExpAttr.enOpType == OP_TYPE_AUTO) ? 0x02 : 0x04;
}

static uint32_t StrmExposureAnsoluteTimeGet(void)
{
    ISP_EXPOSURE_ATTR_S stExpAttr;

    HI_MPI_ISP_GetExposureAttr(0, &stExpAttr);
    return stExpAttr.stManual.u32ExpTime;
}

static void StrmExposureAutoModeSet(uint8_t v)
{
    ISP_EXPOSURE_ATTR_S stExpAttr;

    HI_MPI_ISP_GetExposureAttr(0, &stExpAttr);
    stExpAttr.enOpType = (v == AUTO_MODE_SET_VALUE) ? OP_TYPE_MANUAL : OP_TYPE_AUTO;
    HI_MPI_ISP_SetExposureAttr(0, &stExpAttr);
}

static void StrmExposureAnsoluteTimeSet(uint32_t v)
{
    ISP_EXPOSURE_ATTR_S stExpAttr;

    HI_MPI_ISP_GetExposureAttr(0, &stExpAttr);
    stExpAttr.stManual.u32ExpTime = v * ANSOLUTE_TIME_SET_VALUE;
    stExpAttr.stManual.enExpTimeOpType = OP_TYPE_MANUAL;
    HI_MPI_ISP_SetExposureAttr(0, &stExpAttr);
}

/*************************************************************************************************
    Stream Control Operation Functions End
*************************************************************************************************/
struct processing_unit_ops g_strmIspPuOps = {
    .brightness_get = StrmBrightnessGet,
    .contrast_get = StrmContrastGet,
    .hue_get = StrmHueGet,
    .power_line_frequency_get = StrmPowerLineFrequencyGet,
    .saturation_get = StrmSaturationGet,
    .white_balance_temperature_auto_get = StrmWhiteBalanceTemperatureAutoGet,
    .white_balance_temperature_get = StrmWhiteBalanceTemperatureGet,

    .brightness_set = StrmBrightnessSet,
    .contrast_set = StrmContrastSet,
    .hue_set = StrmHueSet,
    .power_line_frequency_set = StrmPowerLineFrequencySet,
    .saturation_set = StrmSaturationSet,
    .white_balance_temperature_auto_set = StrmWhiteBalanceTemperatureAutoSet,
    .white_balance_temperature_set = StrmWhiteBalanceTemperatureSet,
};

struct input_terminal_ops g_strmIspItOps = {
    .exposure_ansolute_time_get = StrmExposureAnsoluteTimeGet,
    .exposure_auto_mode_get = StrmExposureAutoModeGet,
    .exposure_ansolute_time_set = StrmExposureAnsoluteTimeSet,
    .exposure_auto_mode_set = StrmExposureAutoModeSet,
};

